<?php

declare(strict_types=1);

namespace common\utils;

use common\enum\ResultCode;
use support\Response;

class Json
{
    // 定义HTTP状态码范围常量
    private const HTTP_STATUS_CODE_MIN = 100;
    private const HTTP_STATUS_CODE_MAX = 600;
    // 定义特定业务码常量数组
    private const SPECIAL_BUSINESS_CODES = [
        ResultCode::SUCCESS->value,
        ResultCode::FAIL->value,
    ];

    /**
     * 判断是否为HTTP状态码
     */
    private static function isHttpStatusCode(int $code): bool
    {
        return $code >= self::HTTP_STATUS_CODE_MIN && $code < self::HTTP_STATUS_CODE_MAX;
    }

    /**
     * 创建JSON响应
     */
    private static function make(int $code, string $msg, mixed $data = null, int $httpCode = 200): Response
    {
        $result = [
            'code' => $code,
            'message' => $msg,
            'data' => self::transfer($data),
        ];
        if (!in_array($code, self::SPECIAL_BUSINESS_CODES, true) && self::isHttpStatusCode($code)) {
            $httpCode = $code;
        }
        return new Response($httpCode, ['Content-Type' => 'application/json'], json_encode($result));
    }

    /**
     * 成功响应
     */
    public static function success(mixed $data = null, ?string $message = null, int $httpCode = 200): Response
    {
        $message = $message ?? ResultCode::SUCCESS->getDescription();
        return self::make(ResultCode::SUCCESS->value, $message, $data, $httpCode);
    }

    /**
     * 失败响应
     */
    public static function error(string | ResultCode $obj, mixed $data = null, ?int $httpCode = null): Response
    {
        if (is_string($obj)) {
            $code = ResultCode::FAIL->value;
            $msg = $obj;
        } else {
            $code = $obj->value;
            $msg = $obj->getDescription();
        }
        $httpCode = $httpCode ?? 200;
        return self::make($code, $msg, $data, $httpCode);
    }

    /**
     * 处理响应数据
     */
    private static function transfer(mixed $data): mixed
    {
        if ($data === null) {
            return new \stdClass(); // 返回空对象而非null
        }
        if (is_array($data) || is_object($data)) {
            return Convert::longNumbersToString($data);
        }
        return $data;
    }
}